﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace Job.Core.Imaging
{
    #region ImageExtensions
    /// <summary>
    /// 对 Image 类扩展。
    /// </summary>
    public static class ImageExtensions
    {
        /// <summary>
        /// 对图像生成缩略图。
        /// </summary>       
        /// <param name="width">生成宽度。</param>
        /// <param name="height">生成高度。</param>
        /// <param name="offsetX">相对原始图片X轴偏移量。</param>
        /// <param name="offsetY">相对原始图片Y轴偏移量。</param>
        /// <param name="mode">处理模式。</param>
        /// <returns>缩略图对象。</returns>
        public static Image Thumbnail(this Image image, int width, int height, int offsetX, int offsetY, ThumbnailMode mode)
        {
            if (image == null)
                throw new ArgumentNullException("image");

            int oldWidth = image.Width;
            int oldHeight = image.Height;
            if (oldWidth <= width && oldHeight <= height)
                return image;

            switch (mode)
            {
                case ThumbnailMode.Proportion:
                    //等比缩放。
                    if (oldWidth > oldHeight)
                        height = (int)(oldHeight * ((Decimal)width / oldWidth));
                    else
                        width = (int)(oldWidth * ((Decimal)height / oldHeight));
                    break;
                case ThumbnailMode.Cut:
                    //裁剪。
                    oldWidth = width;
                    oldHeight = height;
                    break;
                case ThumbnailMode.Absolute:
                    //绝对大小。
                    break;
            }

            Bitmap newImg = new Bitmap(width, height);
            Graphics grs = Graphics.FromImage(newImg);

            try
            {
                grs.SmoothingMode = SmoothingMode.HighQuality;
                grs.CompositingQuality = CompositingQuality.HighQuality;
                grs.DrawImage(image, new Rectangle(0, 0, width, height), offsetX, offsetY, oldWidth, oldHeight, GraphicsUnit.Pixel);
                return newImg;
            }
            finally
            {
                grs.Dispose();
                //清理旧对象。
                image.Dispose();
            }
        }

        /// <summary>
        /// 对图像生成缩略图。
        /// </summary>
        /// <param name="width">生成宽度。</param>
        /// <param name="height">生成高度。</param>
        /// <param name="mode">处理模式。</param>
        /// <returns>缩略图对象。</returns>
        public static Image Thumbnail(this Image image, int width, int height, ThumbnailMode mode)
        {
            return image.Thumbnail(width, height, 0, 0, mode);
        }

        /// <summary>
        /// 对图像添加文字水印。
        /// </summary>
        /// <param name="text">文字。</param>
        /// <param name="font">字体。</param>
        /// <param name="color">颜色。</param>
        /// <param name="alpha">透明度(0-255之间)。</param>
        /// <param name="position">水印位置。</param>
        /// <returns>添加水印后的图对象。</returns>
        public static Image WaterText(this Image image, string text, Font font, Color color, int alpha, WaterPosition position)
        {
            if (image == null)
                throw new ArgumentNullException("image");            

            if (string.IsNullOrEmpty(text))
                return image;

            if (font == null)
                throw new ArgumentNullException("font");

            if (color == null)
                throw new ArgumentNullException("color");

            if (alpha < 0 || alpha > 255)
                throw new ArgumentOutOfRangeException("alpha");

            Graphics g = Graphics.FromImage(image);           
            SizeF crSize = g.MeasureString(text, font);
            float offsetX = 0F;
            float offsetY = 0F;

            switch (position)
            {
                case WaterPosition.LeftTop:
                    offsetX = image.Width * .02F;
                    offsetY = image.Height * .02F;
                    break;
                case WaterPosition.CenterTop:
                    offsetX = (image.Width * .50F) - (crSize.Width / 2);
                    offsetY = image.Height * .02F;
                    break;
                case WaterPosition.RightTop:
                    offsetX = (image.Width * .98F) - crSize.Width;
                    offsetY = image.Height * 02F;
                    break;
                case WaterPosition.Left:
                    offsetX = image.Width * .02F;
                    offsetY = (image.Height * .50F) - (crSize.Height / 2);
                    break;
                case WaterPosition.Center:
                    offsetX = (image.Width * .50F) - (crSize.Width / 2);
                    offsetY = (image.Height * .50F) - (crSize.Height / 2);
                    break;
                case WaterPosition.Right:
                    offsetX = (image.Width * .98F) - crSize.Width;
                    offsetY = (image.Height * .50F) - (crSize.Height / 2);
                    break;
                case WaterPosition.LeftBottom:
                    offsetX = image.Width * .02F;
                    offsetY = (image.Height * .98F) - crSize.Height;
                    break;
                case WaterPosition.CenterBottom:
                    offsetX = (image.Width * .50F) - (crSize.Width / 2);
                    offsetY = (image.Height * .98F) - crSize.Height;
                    break;
                case WaterPosition.RightBottom:
                    offsetX = (image.Width * .98F) - crSize.Width;
                    offsetY = (image.Height * .98F) - crSize.Height;
                    break;
            }

            try
            {               
                g.DrawString(text, font, new SolidBrush(Color.FromArgb(alpha, color)), offsetX, offsetY);
                return image;
            }
            finally
            {
                font.Dispose();
                g.Dispose();
            }
        }

        /// <summary>
        /// 对图像添加文字水印。
        /// </summary>
        /// <param name="text">文字。</param>       
        /// <param name="color">颜色。</param>
        /// <param name="alpha">透明度(0-255之间)。</param>
        /// <param name="position">水印位置。</param>
        /// <returns>添加水印后的图对象。</returns>
        public static Image WaterText(this Image image, string text, Color color, int alpha, WaterPosition position)
        {
            return image.WaterText(text, new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Pixel), color, alpha, position);
        }

        /// <summary>
        /// 对图像添加图片水印。
        /// </summary>
        /// <param name="waterFile">图片水印文件。</param>
        /// <param name="alpha">透明度(0-255)。</param>
        /// <param name="position">水印位置。</param>
        /// <returns>添加水印后的图对象。</returns>
        public static Image WaterImage(this Image image, string waterFile, int alpha, WaterPosition position)
        {
            if (image == null)
                throw new ArgumentNullException("image");

            if (string.IsNullOrEmpty(waterFile))
                throw new ArgumentNullException("waterFile");

            if (!File.Exists(waterFile))
                throw new FileNotFoundException(string.Empty, waterFile);

            if (alpha < 0 || alpha > 255)
                throw new ArgumentOutOfRangeException("alpha");

            Image waterImg = null;
            Graphics g = null;
            ImageAttributes attrs = null;

            float offsetX = 0F;
            float offsetY = 0F;

            try
            {
                waterImg = Image.FromFile(waterFile);
                g = Graphics.FromImage(image);
                attrs = new ImageAttributes();
                ColorMatrix matrix = new ColorMatrix();
                //设置透明度。
                matrix.Matrix33 = alpha / 255F;
                attrs.SetColorMatrix(matrix);

                switch (position)
                {
                    case WaterPosition.LeftTop:
                        offsetX = image.Width * .02F;
                        offsetY = image.Height * .02F;
                        break;
                    case WaterPosition.CenterTop:
                        offsetX = (image.Width * .50F) - (waterImg.Width / 2);
                        offsetY = image.Height * .02F;
                        break;
                    case WaterPosition.RightTop:
                        offsetX = (image.Width * .98F) - waterImg.Width;
                        offsetY = image.Height * 02F;
                        break;
                    case WaterPosition.Left:
                        offsetX = image.Width * .02F;
                        offsetY = (image.Height * .50F) - (waterImg.Height / 2);
                        break;
                    case WaterPosition.Center:
                        offsetX = (image.Width * .50F) - (waterImg.Width / 2);
                        offsetY = (image.Height * .50F) - (waterImg.Height / 2);
                        break;
                    case WaterPosition.Right:
                        offsetX = (image.Width * .98F) - waterImg.Width;
                        offsetY = (image.Height * .50F) - (waterImg.Height / 2);
                        break;
                    case WaterPosition.LeftBottom:
                        offsetX = image.Width * .02F;
                        offsetY = (image.Height * .98F) - waterImg.Height;
                        break;
                    case WaterPosition.CenterBottom:
                        offsetX = (image.Width * .50F) - (waterImg.Width / 2);
                        offsetY = (image.Height * .98F) - waterImg.Height;
                        break;
                    case WaterPosition.RightBottom:
                        offsetX = (image.Width * .98F) - waterImg.Width;
                        offsetY = (image.Height * .98F) - waterImg.Height;
                        break;
                }

                g.DrawImage(waterImg, new Rectangle((int)offsetX, (int)offsetY, waterImg.Width, waterImg.Height), 0, 0, waterImg.Width, waterImg.Height, GraphicsUnit.Pixel, attrs);

                return image;
            }
            finally
            {
                if (attrs != null) attrs.Dispose();
                if (g != null) g.Dispose();
                if (waterImg != null) waterImg.Dispose();
            }
        }
    }
    #endregion

    #region ThumbnailMode

    /// <summary>
    /// 缩略图处理方式。
    /// </summary>
    public enum ThumbnailMode
    {
        /// <summary>
        /// 按比例缩略(不变形)。
        /// </summary>
        Proportion,
        /// <summary>
        /// 按指定宽高缩放(可能变形)。
        /// </summary>
        Absolute,
        /// <summary>
        /// 载剪。
        /// </summary>
        Cut
    }

    #endregion

    #region WaterPosition

    /// <summary>
    /// 水印位置。
    /// </summary>
    public enum WaterPosition
    {
        /// <summary>
        /// 左上方。
        /// </summary>
        LeftTop,
        /// <summary>
        /// 左上方。
        /// </summary>
        CenterTop,
        /// <summary>
        /// 右上方。
        /// </summary>
        RightTop,
        /// <summary>
        /// 居左。
        /// </summary>
        Left,
        /// <summary>
        /// 居中。
        /// </summary>
        Center,
        /// <summary>
        /// 居右。
        /// </summary>
        Right,
        /// <summary>
        /// 左下方。
        /// </summary>
        LeftBottom,
        /// <summary>
        /// 左下方。
        /// </summary>
        CenterBottom,
        /// <summary>
        /// 右下方。
        /// </summary>
        RightBottom
    }

    #endregion
}
